/*
 * @Author: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @Date: 2025-09-20 17:58:11
 * @LastEditors: 来自火星的码农 15122322+heyzhi@user.noreply.gitee.com
 * @LastEditTime: 2025-10-03 14:47:21
 * @FilePath: /GateServer/src/net/httpconnection.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "httpconnection.h"
#include "logicsystem.h"
#include <algorithm>
#include <boost/asio/io_context.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/string_type.hpp>
#include <boost/beast/http/error.hpp>
#include <boost/beast/http/field.hpp>
#include <boost/beast/http/impl/read.hpp>
#include <boost/beast/http/impl/write.hpp>
#include <boost/beast/http/status.hpp>
#include <boost/beast/http/verb.hpp>
#include <boost/core/ignore_unused.hpp>
#include <cstddef>
#include <exception>
#include <iomanip>
#include <ios>
#include <sstream>
#include <string>
#include <strstream>
#include "logicsystem.h"
#include "regex.h"
#include "../util/logger.h"
namespace Yizhi{
    HttpConnection::HttpConnection(net::io_context& ioc)
    :m_socket(ioc){

    }

    void HttpConnection::start(){
        auto self=shared_from_this();
        http::async_read(m_socket,m_buf,m_request,[self](beast::error_code err,std::size_t bytes_transfererd){
            try{
                if(err){
                    return ;
                }
                boost::ignore_unused(bytes_transfererd);
                self->HandleReq();
                self->CheckDeadline();
            }

            catch(std::exception& exp){
                LOG_ERROR(exp.what());
            }
        });
    }

    void HttpConnection::HandleReq(){
        m_response.version(m_request.version());
        m_response.keep_alive(false);

        if(m_request.method()==http::verb::get){
            Preparseparams();
            bool success=Yizhi::Lcsym::GetInstance()->HandleGet(m_get_url,shared_from_this());
            if(!success){
                m_response.result(http::status::bad_request);
                m_response.set(http::field::content_type,"text/pain");
                beast::ostream(m_response.body())<<"url not found";
                WriteResponse();
                return;
            }
        }
        else if(m_request.method()==http::verb::post){
            bool success=Yizhi::Lcsym::GetInstance()->HandlePost(m_request.target().to_string(),shared_from_this());
            if(!success){
                m_response.result(http::status::bad_request);
                m_response.set(http::field::content_type,"text/pain");
                beast::ostream(m_response.body())<<"url not found";
                WriteResponse();
                return;
            }
        }
        m_response.set(http::field::server,"GateServer");
        WriteResponse();
        m_response.result(http::status::ok);
        return;
    }





    void HttpConnection::WriteResponse(){
        auto self=shared_from_this();
        m_response.content_length(m_response.body().size());
        http::async_write(m_socket,m_response,[self](beast::error_code err,std::size_t){
            self->m_socket.shutdown(tcp::socket::shutdown_send,err);
            self->m_deadline.cancel();
        });
    }






    void HttpConnection::CheckDeadline(){
        auto self=shared_from_this();
        m_deadline.async_wait(
            [self](beast::error_code ec){
                if(!ec){
                    self->m_socket.close(ec);
                }
            }
        );
    }




    std::string UrlEncode(const  std::string& str){
        std::ostringstream encode;
        encode.fill('0');
        encode<<std::hex;
        for(auto & c:str){
            if(c=='-'||c=='~'||c=='.'||c=='_'){
                encode<<c;
            }
            else if(c==' '){
                encode<<'+';
            }
            else{
                encode<<std::setw(2)<<static_cast<int>(c);
            }
        }
        return encode.str();
    }

    std::string UrlDecode(const std::string &str){
        std::string result;
        for(size_t i=0;i<str.size();i++){
            
            if(str[i]=='+'){
                result+=' ';
            }
            else if(str[i]=='%'&&i+2<str.size()){
                std::string substr=str.substr(i,2);
                int value;
                std::istringstream decode(substr);
                
                if(decode>>std::hex>>value){
                    result+=static_cast<char>(value);
                }
                else{
                    result+=str[i];
                }
                i+=2;
            }
            else{
                result+=str[i];
            }
        }

        return result;
    }


    void HttpConnection::Preparseparams(){
        auto url=m_request.target();
       
        auto querry_pos=url.find('?');
        if(querry_pos==std::string::npos){
            m_get_url=(std::string)url;
            return;
        }
        m_get_url=(std::string)url.substr(0,querry_pos);
        auto tmp=url.substr(querry_pos+1);
        size_t start=0;
        while(start<tmp.size()){
            size_t end=tmp.find('&',start);
            if(end==std::string::npos){
                end=tmp.length();
            }

            auto pair=tmp.substr(start,end);
            beast::string_view key;
            beast::string_view value;
            if(!pair.empty()){
                size_t pos=pair.find('=');
                if(pos!=std::string::npos){
                    key=pair.substr(0,pos);
                    value=pair.substr(pos+1);
                   
                }
                else {
                   continue;
                }

                if(!key.empty()){
                      m_getparams[UrlEncode(key.to_string())]=UrlEncode(value.to_string());
                }
               
            }
            start=end+1;
        }   
    }
}
